import org.junit
import org.junit.Test

import scala.collection.mutable.ArrayBuffer


/**
  * Created by ade on 2017/6/13.
  */
object TestScalaArrays {
  //  def main(args: Array[String]) {
  //    val a = List(1,2,3,4)
  //    val c = a.par.aggregate(5)(seqno,combine)
  //    println("c:"+c)
  //  }
  //  def seqno(m:Int,n:Int): Int ={
  //    val s = "seq_exp=%d+%d"
  //    println(s.format(m,n))
  //    return m+n
  //  }
  //  def combine(m:Int,n:Int): Int ={
  //    val s = "com_exp=%d+%d"
  //    println(s.format(m,n))
  //    return m+n
  //  }
  //  /**
  //    seq_exp=5+3
  //    seq_exp=5+2
  //    seq_exp=5+4
  //    seq_exp=5+1
  //    com_exp=6+7
  //    com_exp=8+9
  //    com_exp=13+17
  //    c:30
  //    */
}

class TestScalaArrays {

  @junit.Test
  def testZipWithIndex(): Unit ={
    val a = Array(10,20,30,40)
    val b = a.zipWithIndex
    println(b.mkString(","))        //(10,0),(20,1),(30,2),(40,3)
  }
  @junit.Test
  def testZipAll(): Unit ={
//    val a = Array(1,2,3,4,5,6,7)
//    val b = Array(5,4,3,2,1)
//    val c = a.zipAll(b,9,8)         //(1,5),(2,4),(3,3),(4,2),(5,1),(6,8),(7,8)


    val a = Array(1,2,3,4)
    val b = Array(5,4,3,2,1)
    val c = a.zipAll(b,9,8)         //(1,5),(2,4),(3,3),(4,2),(9,1)
    println(c.toBuffer)
  }

  @junit.Test
  def testZip(): Unit ={
    val a = Array(1,2,3,4,5)
    val b = Array(5,4,3,2,1)
    val c = a.zip(b)
    println(c.mkString(","))        //(1,5),(2,4),(3,3),(4,2),(5,1)
  }

  @junit.Test
  def testWithFilter(): Unit ={
    val a = Array(1,2,3,4,5)
    val b = a.withFilter( {x:Int => x>3}).map(x=>x)
    println(b.mkString(","))        //4,5
  }

  @junit.Test
  def testView(): Unit ={
    val a = Array(1,2,3,4,5)
    val b = a.view(1,3)
    println(b.mkString(","))        //2,3
  }

  @junit.Test
  def testUpdated(): Unit ={
    val a = Array(1,2,3,4,5)
    val b = a.updated(1,9)
    println(b.mkString(","))        //1,9,3,4,5
  }

  @junit.Test
  def testUpdate(): Unit = {
    val a = Array(1,2,3,4,5)
    a.update(1,9)
    println(a.mkString(","))        //1,9,3,4,5
  }

  @junit.Test
  def testUnzip3(): Unit = {
    val chars = Array(("a", "b", "x"), ("c", "d", "y"), ("e", "f", "z"))
    val b = chars.unzip3
    println(b._1.mkString(",")) //a,c,e
    println(b._2.mkString(",")) //b,d,f
    println(b._3.mkString(",")) //x,y,z
  }

  @junit.Test
  def testUnzip(): Unit = {
    val chars = Array(("a", "b"), ("c", "d"))
    val b = chars.unzip
    println(b._1.mkString(",")) //a,c
    println(b._2.mkString(",")) //b,d
  }


  @junit.Test
  def testUnion(): Unit = {
    val a = Array(1, 2, 3, 4, 5)
    val b = Array(6, 7)
    val c = a.union(b)
    println(c.mkString(",")) // 1,2,3,4,5,6,7
  }

  @junit.Test
  def testTranspose(): Unit = {
    val chars = Array(Array("a", "b"), Array("c", "d"), Array("e", "f"))
    val b = chars.transpose
    println(b(0).mkString(","))
    println(b(1).mkString(","))
  }

  @junit.Test
  def testToMap(): Unit = {
    val chars = Array(("a", "b"), ("c", "d"), ("e", "f"))
    val b = chars.toMap
    println(b) //Map(a -> b, c -> d, e -> f)
  }

  @junit.Test
  def testSubSequence(): Unit = {
    val chars = Array('a', 'b', 'c', 'd')
    val b = chars.subSequence(1, 3)
    println(b.toString) //  bc
  }

  @junit.Test
  def testStringPrefix(): Unit = {
    val a = Array(0, 1, 2, 3, 4, 5)
    println(a.toString()) //[I@3daa57fb
    val b = a.stringPrefix
    println(b) //[I
  }

  @junit.Test
  def testStartWith(): Unit = {
    val a = Array(0, 1, 2, 3, 4, 5)
    val b = Array(1, 2)
    println(a.startsWith(b, 1)) //  true
  }

  @junit.Test
  def testSplitAt(): Unit = {
    val a = Array(3, 2, 1, 4, 5)
    val b = a.splitAt(2)
    println(b._1.mkString(",")) //  3,2
    println(b._2.mkString(",")) //  1,4,5
  }

  @junit.Test
  def testSpan(): Unit = {
    val a = Array(3, 2, 1, 4, 5)
    val b = a.span({ x: Int => x > 2 })
    println(b._1.mkString(",")) //  3
    println(b._2.mkString(",")) //  2,1,4,5
  }

  @junit.Test
  def testSorted(): Unit = {
    val a = Array(3, 2, 1, 4, 5)
    val b = a.sorted
    println(b.mkString(",")) // 1,2,3,4,5
  }

  @junit.Test
  def testSortWith(): Unit = {
    val a = Array(3, 2, 1, 4, 5)
    val b = a.sortWith(_.compareTo(_) > 0) // 大数在前
    println(b.mkString(",")) // 5,4,3,2,1
  }

  @junit.Test
  def testSortBy(): Unit = {
    val a = Array(3, 2, 1, 4, 5)
    val b = a.sortBy({ x: Int => x })
    println(b.mkString(",")) // 1,2,3,4,5
  }

  @junit.Test
  def testSlid2(): Unit = {
    val a = Array(1, 2, 3, 4, 5)
    val b = a.sliding(3, 2).toList //第一个从1开始， 第二个从3开始，因为步进是 2
    for (i <- 0 to b.length - 1) {
      val s = "第%d个：%s"
      println(s.format(i, b(i).mkString(",")))
    }

    /**
      * 第0个：1,2,3
      * 第1个：3,4,5
      */
  }

  @junit.Test
  def testSlid(): Unit = {
    val a = Array(1, 2, 3, 4, 5)
    val b = a.sliding(3).toList
    for (i <- 0 to b.length - 1) {
      val s = "第%d个：%s"
      println(s.format(i, b(i).mkString(",")))
    }

    /**
      * 第0个：1,2,3
      * 第1个：2,3,4
      * 第2个：3,4,5
      */
  }

  @junit.Test
  def testSlice(): Unit = {
    val a = Array(1, 2, 3, 4, 5)
    val b = a.slice(1, 3)
    println(b.mkString(",")) // 2,3
  }

  @junit.Test
  def testSeglementsLength(): Unit = {
    val a = Array(1, 2, 3, 2, 2, 2, 2, 2, 2, 5)
    val b = a.segmentLength({ x: Int => x < 3 }, 3) // 5
    println(b)
  }


  @junit.Test
  def testScan(): Unit = {
    val a = Array(1, 2, 3, 4, 5)
    val b = a.scan(5)(seqno)
    println(b.mkString(",")) // 5,6,8,11,15,20
  }

  @junit.Test
  def testSameElements(): Unit = {
    val a = Array(1, 2, 3, 4, 5)
    val b = Array(1, 2, 3, 4, 5)
    println(a.sameElements(b)) // true

    val c = Array(1, 2, 3, 5, 4)
    println(a.sameElements(c)) // false
  }

  @junit.Test
  def testReverseMap(): Unit = {
    val a = Array(1, 2, 3, 4, 5)
    val b = a.reverseMap({ x: Int => x * 10 })
    println(b.mkString(",")) // 50,40,30,20,10
  }

  @junit.Test
  def testReverse(): Unit = {
    val a = Array(1, 2, 3, 4, 5)
    val b = a.reverse
    println(b.mkString(",")) //5,4,3,2,1
  }

  @junit.Test
  def testReduce(): Unit = {
    val fun: PartialFunction[Any, Int] = {
      case 'a' => 'A'
      case x: Int => x * 100
    }

    val a = Array(1, 2, 3, 4, 5)
    val b = a.reduce(_ + _)
    println(b) // 15
    /**
      * seq_exp=1+2
      * seq_exp=3+3
      * seq_exp=6+4
      * seq_exp=10+5
      */
  }

  def seqno(m: Int, n: Int): Int = {
    val s = "seq_exp=%d+%d"
    println(s.format(m, n))
    return m + n
  }

  def combine(m: Int, n: Int): Int = {
    val s = "com_exp=%d+%d"
    println(s.format(m, n))
    return m + n
  }

  @junit.Test
  def testPrefixLength(): Unit ={
    val a = Array(1,2,3,4,1,2,3,4)
    val b = a.prefixLength( {x:Int => x<3}) // b = 2
    println(b)
  }

  @junit.Test
  def testCombinations(): Unit ={
    val a = Array(1, 2, 3, 4, 5)
    val b = a.permutations.toList   // b 中将有120个结果，知道排列组合公式的，应该不难理解吧
    /**如果是combinations*/
    val bb = a.combinations(5).toList    // b 中只有一个，因为不管怎样排列，都是这5个数字组成，所以只能保留第一个
    println(bb(0).toBuffer)
  }

  // 替换
  @junit.Test
  def testPacth(): Unit ={
    val a = Array(1, 2, 3, 4, 5)
    val b = Array(3, 4, 6)
    val c = a.patch(1,b,2)
    println(c.mkString(","))    // return 1,3,4,6,4,5
    /**从 a 的第二个元素开始，取两个元素，即 2和3 ，这两个元素被替换为 b的内容*/
  }

  @junit.Test
  // 分片
  def testPartition(): Unit ={
    val a = Array(1, 2, 3, 4, 5)
    val b:(Array[Int],Array[Int]) = a.partition( {x:Int => x % 2 == 0})
    println(b._1.mkString(","))     // return  2,4
    println(b._2.mkString(","))     // return  1,3,5
  }

  @junit.Test
  // 返回一个并行实现，产生的并行序列，不能被修改
  def testPar(): Unit ={
    val a = Array(1, 2, 3, 4, 5)
    val b = a.par   //  "ParArray" size = 5
  }

  @junit.Test
  def testPadTo(): Unit ={
    val a = Array(1, 2, 3, 4, 5)
    val b = a.padTo(7,9)    //需要一个长度为 7  的新序列，空出的填充 9
    println(b.mkString(","))    // return  1,2,3,4,5,9,9
  }

  @junit.Test
  def testMinBy(): Unit ={
    val a = Array(1, 2, 3, 4, 5)
    println(a.maxBy( {x:Int => x > 2})) // return  3
  }

  @junit.Test
  def testMap2(): Unit ={
    val a = Array(1, 2, 3, 4, 5)
    val b = a.map( {x:Int => x*10})
    println(b.mkString(","))    // 10,20,30,40,50
  }

  @junit.Test
  def testLengthCompare(): Unit = {
    val aa = Array(2, 3, 4, 5)
    println(aa.lengthCompare(4))
  }

  @junit.Test
  def testLastIndexWhere2(): Unit = {
    val a = Array(1, 4, 2, 3, 4, 5, 1, 4)
    val b = Array(1, 4)
    println(a.lastIndexWhere({ x: Int => x < 2 }, 2)) // return  0
  }

  @junit.Test
  def testLastIndexWhere(): Unit = {
    val a = Array(1, 4, 2, 3, 4, 5, 1, 4)
    println(a.lastIndexWhere({ x: Int => x < 2 }))
  }

  @junit.Test
  def testLastIndexofSlience(): Unit = {
    val a = Array(1, 4, 2, 3, 4, 5, 1, 4)
    val b = Array(1, 4)
    println(a.lastIndexOfSlice(b)) // return  6
  }

  @junit.Test
  def testLastIndexof(): Unit = {
    val a = Array(1, 4, 2, 3, 4, 5)
    println(a.lastIndexOf(4, 3)) // return  1
  }

  @junit.Test
  def testIsDefinedAt(): Unit = {
    val a = Array(1, 2, 3, 4, 5)
    println(a.isDefinedAt(1)) // true
    println(a.isDefinedAt(4)) // true
    println(a.isDefinedAt(5)) // false
  }

  @junit.Test
  def testIntersect(): Unit = {
    val a = Array(1, 2, 3, 4, 5)
    val b = Array(3, 4, 6)
    val c = a.intersect(b)
    println(c.mkString(",")) //return 3,4
  }

  @junit.Test
  def testInits(): Unit = {
    val a = Array(1, 2, 3, 4, 5)
    val b = a.inits.toList
    for (i <- 1 to b.length) {
      val s = "第%d个值：%s"
      println(s.format(i, b(i - 1).mkString(",")))
    }

    /** 计算结果
      * 第1个值：1,2,3,4,5
      * 第2个值：1,2,3,4
      * 第3个值：1,2,3
      * 第4个值：1,2
      * 第5个值：1
      * 第6个值
      */
  }

  @junit.Test
  def testInit(): Unit = {
    val a = Array(10, 2, 3, 40, 5)
    val b = a.init
    println(b.mkString(",")) // 10, 2, 3, 40
  }

  @junit.Test
  def testIndices(): Unit = {
    val a = Array(10, 2, 3, 40, 5)
    val b = a.indices
    println(b.mkString(",")) // 0,1,2,3,4
  }

  @junit.Test
  def testIndexWhere(): Unit = {
    val a = Array(1, 2, 3, 4)
    println(a.indexWhere({ x: Int => x > 3 }))
  }

  @junit.Test
  def testIndexSlience(): Unit = {
    val a = Array(1, 3, 2, 3, 4)
    val b = Array(2, 3)
    println(a.indexOfSlice(b)) // return 2
  }

  @junit.Test
  def testHasDefiniteSize(): Unit = {
    val a = Array(1, 2, 3, 4, 5)
    println(a.hasDefiniteSize)
  }


  @junit.Test
  def testGroupBy(): Unit = {
    val a = Array(1, 2, 3, 4)
    val b = a.groupBy(x => x match {
      case x if (x < 3) => "small"
      case _ => "big"
    })
    println(b.get("big").get(1))
  }

  @junit.Test
  def testForEach(): Unit = {
    val a = Array(1, 2, 3, 4)
    a.foreach(x => println(x * 10))

    /**
      * 10
      * 20
      * 30
      * 40
      */
  }

  @junit.Test
  def testForAll(): Unit = {
    val a = Array(1, 2, 3, 4)
    val b = a.forall({ x: Int => x > 0 }) //true
    val c = a.forall({ x: Int => x > 2 }) //false
    println(b + "" + c)
  }

  @junit.Test
  def testFlodRight(): Unit = {
    def seqno(m: Int, n: Int): Int = {
      val s = "seq_exp=%d+%d"
      println(s.format(m, n))
      return m + n
    }
    val a = Array(1, 2, 3, 4)
    val b = a.foldRight(5)(seqno)

    /** 运算过程
      * seq_exp=4+5
      * seq_exp=3+9
      * seq_exp=2+12
      * seq_exp=1+14
      */
    /**
      * 简写 (a :\ 5)(_+_)
      */
  }

  @junit.Test
  def testFlodLeft2(): Unit = {
    def seqno(m: Int, n: Int): Int = {
      val s = "seq_exp=%d+%d"
      println(s.format(m, n))
      return m + n
    }
    val a = Array(1, 2, 3, 4)
    val b = a.foldLeft(5)(seqno)

    /** 运算过程
      * seq_exp=5+1
      * seq_exp=6+2
      * seq_exp=8+3
      * seq_exp=11+4
      */
    /**
      * 简写 (5 /: a)(_+_)
      */
  }

  @junit.Test
  def testFlod(): Unit = {
    def seqno(m: Int, n: Int): Int = {
      val s = "seq_exp=%d+%d"
      println(s.format(m, n))
      return m + n
    }
    def combine(m: Int, n: Int): Int = {
      val s = "com_exp=%d+%d"
      println(s.format(m, n))
      return m + n
    }
    val a = Array(1, 2, 3, 4)
    val b = a.fold(5)(seqno)
    /** 运算过程
      * seq_exp=5+1
      * seq_exp=6+2
      * seq_exp=8+3
      * seq_exp=11+4
      */
    val c = a.par.aggregate(5)(seqno, combine)

    /** 运算过程
      * seq_exp=5+1
      * seq_exp=5+4
      * seq_exp=5+3
      * com_exp=8+9
      * seq_exp=5+2
      * com_exp=6+7
      * com_exp=13+17
      */
    println(b)
    println(c)
  }

  @junit.Test
  def testFlatten(): Unit = {
    val dArr = Array(Array(1, 2, 3), Array(4, 5, 6))
    val c = dArr.flatten
    println(c.mkString(","))
  }

  @junit.Test
  def testFlatMap(): Unit = {
    val a = Array(1, 2, 3, 4)
    val b = a.flatMap(x => 1 to x)
    println(b.mkString(","))

    /**
      * 1,1,2,1,2,3,1,2,3,4
      * 从1开始，分别于集合a的每个元素生成一个递增序列，过程如下
      * 1
      * 1,2
      * 1,2,3
      * 1,2,3,4
      */
  }


  @junit.Test
  def testFind(): Unit = {
    val a = Array(1, 2, 3, 4)
    val b = a.find({ x: Int => x > 2 })
    println(b) // Some(3)
  }

  @junit.Test
  def testFilter(): Unit = {
    val a = Array(3, 2, 3, 4)
    val b = a.filter({ x: Int => x > 2 })
    println(b.mkString(",")) //3,3,4
  }

  @junit.Test
  def testExit(): Unit = {
    val a = Array(3, 2, 3, 4)
    println(a.exists({ x: Int => x == 3 })) //true
    println(a.exists({ x: Int => x == 30 })) //false
  }

  @junit.Test
  def endWith(): Unit = {
    val a = Array(3, 2, 3, 4)
    val b = Array(3, 4)
    println(a.endsWith(b)) //true
  }

  @junit.Test
  def testDropWhile(): Unit = {
    //下面去除大于2的，第一个元素 3 满足，它后面的元素 2 不满足，所以返回 2,3,4
    val a = Array(3, 2, 3, 4)
    val c = a.dropWhile({ x: Int => x > 2 })
    println(c.mkString(","))

    //如果数组 a 是下面这样，第一个元素就不满足，所以返回整个数组 1, 2, 3,4
    //    val a = Array(1, 2, 3,4)
  }

  @junit.Test
  def testDrop(): Unit = {
    val a = Array(1, 2, 3, 4)
    val c = a.drop(2)
    println(c.mkString(",")) // 3,4
  }

  @junit.Test
  def testDistince(): Unit = {
    val a = Array(1, 2, 3, 4, 4, 5, 6, 6)
    val c = a.distinct
    println(c.mkString(","))
  }

  @junit.Test
  def testDiff(): Unit = {
    val a = Array(1, 2, 3, 4)
    val b = Array(4, 5, 6, 7)
    val c = a.diff(b)
    println(c.mkString) //1,2,3
  }

  @junit.Test
  def testCount(): Unit = {
    val a = Array(1, 2, 3)
    println(a.count({ x: Int => x > 2 }))
  }

  @junit.Test
  def testCorresponds(): Unit = {
    val a = Array(1, 2, 3)
    val b = Array(4, 3, 6)
    println(a.corresponds(b)(_ < _))
  }

  @junit.Test
  def copyToBuffer(): Unit = {
    val a = Array('a', 'b', 'c')
    val b: ArrayBuffer[Char] = ArrayBuffer()
    a.copyToBuffer(b)
    println(b.mkString(","))
  }

  @junit.Test
  def testCopyToArray(): Unit = {
    val a = Array('a', 'b', 'c')
    val b: Array[Char] = new Array(5)
    a.copyToArray(b)

    /** b中元素 ['a','b','c',0,0] */
    a.copyToArray(b, 1)

    /** b中元素 [0,'a',0,0,0] */
    a.copyToArray(b, 1, 2)

    /** b中元素 [0,'a','b',0,0] */
  }

  @junit.Test
  def testContionSlice(): Unit = {
    val a = List(1, 2, 3, 4)
    val b = List(2, 3)
    println(a.containsSlice(b))
  }

  @junit.Test
  def testCombination(): Unit = {
    val arr = Array("a", "b", "c")
    val newarr = arr.combinations(2)
    newarr.foreach((item) => println(item.mkString(",")))

    /**
      * a,b
      * a,c
      * b,c
      */
  }

  @junit.Test
  // 在序列中查找第一个符合偏函数定义的元素，并执行偏函数计算
  def testPartialFunction(): Unit = {
    val arr = Array('a', 1, "b")
    //定义一个偏函数，要求当被执行对象为Int类型时，进行乘100的操作，对于上面定义的对象arr来说，只有第一个元素符合要求
    val fun: PartialFunction[Any, Int] = {
      case x: Int => x * 100
    }
    //计算
    val myvalue = arr.collectFirst(fun)
    println("myvalue:" + myvalue)
    //另一种写法
    val value = arr.collectFirst({ case x: Int => x * 100 })
    println(value)
  }

  @junit.Test
  def myCollect(): Unit = {
    val chars = Array('a', 'b', 'c')
    //我们通过下面的偏函数，把chars数组的小写a转换为大写的A
    val fun: PartialFunction[Char, Char] = {
      case 'a' => 'A'
      case x => x
    }
    val newchars = chars.collect(fun)
    println("newchars:" + newchars.mkString(","))

    /** 输出结果是 newchars:A,b,c */
  }


  @junit.Test
  def cloneCopy(): Unit = {
    val chars = Array('a', 'b', 'c')
    println(chars.apply(2))
    val newchars = chars.clone()
    println(newchars.toBuffer)
  }

  @junit.Test
  def testChartAt(): Unit = {
    val chars = Array('a', 'b', 'c')
    println("c:" + chars.charAt(0)) //结果 a
  }

  /**
    * 同 main 方法
    */
  @junit.Test
  def testAggregate(): Unit = {
    val a = List(1, 2, 3, 4)
    val c = a.par.aggregate(5)(_ + _, _ + _)
    println(c)
  }


  @junit.Test
  def testAddString2(): Unit = {
    val a = List(1, 2, 3, 4)
    val b = new StringBuilder()
    val c = a.addString(b, "{", ",", "}")
    println("c:  " + c) // c:  {1,2,3,4}
  }


  @junit.Test
  def testAddString(): Unit = {
    val a = List(1, 2, 3, 4)
    val b = new StringBuilder()
    val c = a.addString(b, ",")
    val d = a.mkString("[", ",", "]")
    println("c:  " + c) // c:  1,2,3,4</code>
    println(d)
  }

  @junit.Test
  def test6(): Unit = {
    val a = List(1, 2, 3, 4)
    val b = new StringBuilder()
    val c = a.addString(b) // c中的内容是  1234
    println(c)
  }

  @junit.Test
  def testFlodLeft(): Unit = {
    //对数组中所有的元素进行相同的操作 ，foldLeft的简写
    val a = List(1, 2, 3, 4)
    val c = (10 /: a) (_ + _) // 1+2+3+4+10
    val d = (10 /: a) (_ * _) // 1*2*3*4*10
    println("c:" + c) // c:20
    println("d:" + d) // d:240
  }

  @junit.Test
  def testAddMao(): Unit = {
    val a = List(1, 2)
    val c = 0 +: a // c中的内容是 （0,1,2）
    println(c.toBuffer)
  }

  @junit.Test
  def testAddAddMao(): Unit = {
    val a = List(1, 2)
    println(a.getClass.getName)
    val b = scala.collection.mutable.LinkedList(3, 4)
    //跟后边的相关，也就是是按照后面的来的
    val c = a ++: b
    println(c.toBuffer)
    println(c.getClass().getName())
  }

  @junit.Test
  def testAddAdd(): Unit = {
    val a = Array(1, 2)
    val b = Array(3, 4)
    val c = a ++ b
    println(c.toBuffer)
  }

  @Test
  def testMap(): Unit = {
    val numbers = Array(1, 2, 3, 4) //声明一个数组对象
    val first = numbers(0) // 读取第一个元素
    println(first)
    numbers(3) = 100 // 替换第四个元素为100
    val biggerNumbers = numbers.map(_ * 2) // 所有元素乘2</code>
    println(biggerNumbers.toBuffer)
  }

}
